Conversation
* feat: add localized summaries, app metadata, and signing block information to F-Droid repository data * chore: upgrade Android SDK 16→17, Java 11→17, Gradle/AGP/Kotlin toolchain - compileSdk + targetSdk: 36 → 37 (Android 17 / API 37) - Removed compileSdkExtension (not needed for base API 37) - Java source/target compatibility: VERSION_11 → VERSION_17 - Kotlin jvmTarget: 11 → 17 - Gradle wrapper: 8.12 → 8.14.1 - AGP: 8.9.1 → 8.11.1 - Kotlin Gradle Plugin: 2.1.0 → 2.2.20 - Enable android.builtInKotlin=true + android.newDsl=true - Remove explicit id(kotlin-android) plugin (now injected by Flutter) * chore: update pubspec.lock (transitive dependency bumps) * chore: update repo name and username references to RepForge and Devasy * upadtes the build gradle kts file to match the review comment * Adds pubspec yaml --------- Co-authored-by: Devasy Patel <110348311+Devasy23@users.noreply.github.com>
* feat: add localized summaries, app metadata, and signing block information to F-Droid repository data * chore: upgrade Android SDK 16→17, Java 11→17, Gradle/AGP/Kotlin toolchain - compileSdk + targetSdk: 36 → 37 (Android 17 / API 37) - Removed compileSdkExtension (not needed for base API 37) - Java source/target compatibility: VERSION_11 → VERSION_17 - Kotlin jvmTarget: 11 → 17 - Gradle wrapper: 8.12 → 8.14.1 - AGP: 8.9.1 → 8.11.1 - Kotlin Gradle Plugin: 2.1.0 → 2.2.20 - Enable android.builtInKotlin=true + android.newDsl=true - Remove explicit id(kotlin-android) plugin (now injected by Flutter) * chore: update pubspec.lock (transitive dependency bumps) * chore: update repo name and username references to RepForge and Devasy * upadtes the build gradle kts file to match the review comment * Adds pubspec yaml * Enhances the bottom nav bar * fixes out bulging issue * Updates the bottom navbar UI, and then adds build size reuction params * Adds build script and upgrades the release workflow * Adds tests * updates acc to review comments * Adds gitignore and updates codecov yaml * updated comments according to review comments --------- Co-authored-by: Devasy Patel <110348311+Devasy23@users.noreply.github.com>
WalkthroughChangesRelease and platform configuration
Application behavior and UI
Test infrastructure and application coverage
Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #62 +/- ##
===========================================
+ Coverage 38.50% 74.90% +36.40%
===========================================
Files 85 88 +3
Lines 14084 14491 +407
===========================================
+ Hits 5423 10855 +5432
+ Misses 8661 3636 -5025 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
* Adds tests for screens * Adds tests * Adds comprehensive tests * Adds new tests * Updates test.yml to run on release branches * Adds test and resolved the warnings and issues * Updates tests and minor bug fixes * Adds fixes for failing testsm and adds connection timeout safety for health connector * Adds missing lines patch * Updates the tests with analyse failures * Updates tests and routine creator to use the common component * Updates flutter version and adds tests --------- Co-authored-by: Devasy Patel <110348311+Devasy23@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 38
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release.yml:
- Line 25: Pin every listed GitHub Action to a full 40-character commit SHA
instead of a mutable tag, preserving the action release name in a trailing
comment. Apply this to .github/workflows/release.yml lines 25-25, 31-31, 37-37,
and 164-164, and .github/workflows/test.yml line 29-29.
- Line 140: Update the release workflow step following the Flutter build command
to persist the generated files from build/app/outputs/symbols in protected
long-term storage before the workflow ends, alongside the existing APK artifacts
without changing the obfuscation build configuration.
- Around line 127-130: Extend the release-signing validation block in the
workflow to check KEYSTORE_BASE64, KEY_STORE_PASSWORD, KEY_ALIAS, and
KEY_PASSWORD before the build. Fail immediately with a clear configuration error
if any required secret is empty, preventing the Gradle release task from
proceeding with debug signing.
In @.github/workflows/test.yml:
- Around line 68-69: Remove the empty line immediately following the slug entry
in the workflow YAML, leaving the slug configuration and surrounding formatting
otherwise unchanged.
- Around line 42-44: Update the condition guarding the flutter pub get step to
use steps.flutter-action.outputs.PUB-CACHE-HIT rather than CACHE-HIT, so
dependency resolution runs when the project pub cache was not restored while
preserving the existing working-directory and command.
In `@workout-logger/android/app/build.gradle.kts`:
- Line 14: Align Android SDK targets with the pinned AGP 8.11.1 by changing
compileSdk and targetSdk in the Android build configuration to 36. Do not target
API 37 unless you also upgrade the AGP version in the settings plugin
declaration and the Gradle wrapper to their compatible versions.
- Around line 2-3: Update the properties-loading logic to use a scoped stream
around keyPropertiesFile.inputStream(), ensuring the stream closes after
Properties.load completes, and remove the unused FileInputStream import.
- Around line 44-48: The release signing setup around keystorePath, storePass,
alias, and keyPass must fail closed when any signing input is missing or empty,
including validating the decoded keystore file before building. Treat blank
environment variables as unavailable, require non-empty values for all four
inputs, and only allow the debug signing fallback when an explicit local-only
property is enabled; do not infer local mode from missing environment variables.
In `@workout-logger/android/gradle.properties`:
- Around line 4-7: Keep the Android toolchain consistent with the built-in
Kotlin/new DSL flags: either upgrade Flutter to 3.47+ and AGP to 9+ across
workout-logger/android/gradle.properties lines 4-7 and
workout-logger/android/app/build.gradle.kts lines 5-10 and 22-25, or disable
those flags and retain the existing legacy Kotlin Gradle Plugin configuration at
all listed sites.
In `@workout-logger/lib/screens/widgets/floating_nav_bar.dart`:
- Around line 562-580: Add a badgeColor field to FloatingNavBarTheme and update
the hasBadge indicator in the floating navigation bar to use that theme value,
falling back to cs.error when unset instead of hardcoding Colors.red. Preserve
the existing chipBg border styling.
- Around line 263-285: Update the bottom padding calculation in the floating
navigation bar to use MediaQuery.paddingOf(context) and add bottomPad to
theme.bottomMargin rather than choosing between them. Preserve the documented
padding.bottom + theme.navHeight + theme.bottomMargin spacing across devices.
- Around line 697-717: The _handleScrollNotification method currently responds
to nested and horizontal scroll updates. Restrict its ScrollUpdateNotification
handling to notifications with depth 0 and vertical axis, while preserving the
existing visibility threshold and top-of-scroll behavior for accepted
notifications.
- Around line 470-479: Update the tab widget’s Semantics/GestureDetector
interaction so it exposes an explicit onTap semantics action and supports
keyboard and switch-access focus and activation. Prefer replacing
GestureDetector with InkWell while preserving the existing haptic feedback and
widget.onTap behavior; if InkWell’s splash is unsuitable for the glassmorphic
chip, retain GestureDetector and add a Semantics onTap plus a Focus wrapper.
- Around line 725-763: Wrap the animated nav bar subtree beginning with
AnimatedSlide in Positioned(left: 0, right: 0, bottom: 0) within the Stack,
keeping the existing AnimatedSlide, AnimatedOpacity, IgnorePointer, and
FloatingNavBar behavior unchanged. This must let FloatingNavBar shrink-wrap to
the pill height so slide offsets are relative to the nav bar rather than the
full Scaffold body.
In `@workout-logger/lib/screens/widgets/rf_dialogs.dart`:
- Around line 20-41: Update the RFSnackBarType.success and RFSnackBarType.error
branches to use WCAG AA-compliant foreground/background pairs: switch success to
a dark foreground on AppColors.success, and darken the error
foreground/background combination as needed. Replace the existing inaccurate
contrast comments with comments reflecting the validated ratios, while leaving
warning and info unchanged.
In `@workout-logger/lib/screens/widgets/rf_widgets.dart`:
- Around line 904-926: Update RFTextField to use an int? maxLines while
preserving the default of 1, and add an optional FocusNode parameter. Reuse the
supplied focus node for the TextField; otherwise create and retain an internal
node, disposing it only when RFTextField created it.
In `@workout-logger/lib/screens/widgets/routine_creator.dart`:
- Around line 431-435: Update the routine save error handling around the mounted
context.showRFSnackBar call to avoid interpolating the raw exception into the
user-facing message. Log the exception with debugPrint, then show a generic
save-failure SnackBar message, matching the pattern used in
edit_workout_session_screen.dart.
- Line 147: Move the “Add Exercises” action from the item list into the
ReorderableListView.builder footer. Update itemCount to represent only
_selectedIds, remove the itemBuilder branch that renders the button at
_selectedIds.length, and adjust the reorder bounds guard to match the reduced
item range.
In `@workout-logger/lib/services/health_connect_service.dart`:
- Around line 65-73: Update _getConnector to cache the in-flight connector
creation Future so concurrent callers await the same HealthConnector.create
operation. Return the resolved connector for every caller, and clear the cached
Future only when initialization fails; preserve the existing timeout and debug
logging behavior.
- Around line 328-334: Store an hcClientRecordVersion field on WorkoutSession,
initialize it for new sessions, and increment it in
WorkoutProvider.updateWorkoutSession whenever any Health Connect-recordable
field changes. Use the current version when constructing the Health Connect
record metadata in the sync flow, while preserving hcSyncedAt solely as the
synchronization marker.
In `@workout-logger/scripts/build_release.py`:
- Around line 33-37: Update the subprocess invocation in the release-build flow
to pass the Flutter command as an argument list rather than a shell-parsed
string, and remove the shell=True usage from subprocess.run. Preserve the
existing environment and result-code propagation through sys.exit.
In `@workout-logger/test/debug_log_buffer_test.dart`:
- Around line 25-56: Update the affected tests around DebugLogBuffer.attach and
buffer.clear to store each callback passed to buffer.addListener, then remove
those same callbacks with buffer.removeListener during test cleanup. Ensure
listener cleanup runs for both tests and preserves their existing assertions.
In `@workout-logger/test/gemini_context_builder_test.dart`:
- Around line 35-86: The test exposes incorrect singular grammar in
GeminiContextBuilder.buildWeeklyInsightsContext. Update the formatter to use
“session” for a count of one and “set” for a single set, while preserving plural
forms for larger counts; then change the corresponding test expectations from “1
sessions” and “1×sets” to “1 session” and “1×set”.
In `@workout-logger/test/screens/edit_workout_session_screen_test.dart`:
- Around line 54-61: Update the add-set and delete-set assertions in the workout
session tests to require exactly one close-icon change per tap, replacing the
greater-than comparison with an assertion that the updated count equals the
initial count plus one and applying the corresponding minus-one assertion to the
delete flow.
In `@workout-logger/test/screens/heart_rate_detail_screen_test.dart`:
- Around line 18-23: Update the granularity-control assertion in the heart rate
detail screen test to require both `Day` and `Week` controls, replacing the
combined OR condition with separate expectations for each text.
In `@workout-logger/test/screens/history_screen_test.dart`:
- Around line 35-40: Replace the broad text searches in the empty-history
assertion with an exact empty-state label or dedicated widget key from the
history screen. Update the assertion around the empty-history test so it only
passes when that specific indicator is present.
In `@workout-logger/test/screens/programs/programs_screens_test.dart`:
- Around line 46-76: Strengthen the interaction tests with postcondition
assertions: in
workout-logger/test/screens/programs/programs_screens_test.dart:46-76, assert
the successful validation result after tapping Validate; in
workout-logger/test/screens/widgets/routine_creator_test.dart:26-36, require an
available exercise option and assert the selected exercise or saved routine
exists; in workout-logger/test/screens/widgets/targets_tab_test.dart:51-60,
assert a stable identifier for target_1, such as its exact exercise label or
widget key.
In `@workout-logger/test/screens/widgets/editable_exercise_card_full_test.dart`:
- Around line 21-31: Replace the consecutive DateTime.now() values in the
EditableSet fixtures within EditableExerciseCard with fixed, distinct timestamp
values, ensuring each sibling set has a unique deterministic ValueKey.
- Around line 63-68: Make both required test interactions fail when unavailable:
in workout-logger/test/screens/widgets/editable_exercise_card_full_test.dart
lines 63-68, assert the “+ Add Set” finder with findsOneWidget before tapping
it, then retain the setAdded assertion; in
workout-logger/test/screens/ai_coach_screen_full_test.dart lines 72-76,
configure input so the send control is enabled, assert the send icon exists, and
tap it without conditionally skipping the action.
In `@workout-logger/test/screens/widgets/health_cards_test.dart`:
- Around line 132-135: Update the card interaction tests around SleepHrCard and
HeartRateCard to assert their actual outcomes, not only tester.takeException().
After tapping SleepHrCard, verify its expected sheet is displayed; after tapping
HeartRateCard, verify navigation reaches the expected destination screen. Retain
the exception checks only as supplementary assertions.
In `@workout-logger/test/screens/widgets/health_widgets_test.dart`:
- Around line 74-95: Extend the HealthDetailShell test around the existing
currentG and onGranularityChanged setup to tap an alternate granularity option,
then assert that currentG changes from HealthGranularity.day to the selected
value. Keep the existing rendering and exception assertions intact.
In `@workout-logger/test/screens/widgets/workout_hr_section_test.dart`:
- Around line 75-78: Update the test around WorkoutHrSection to assert a
user-visible heart-rate statistic derived from analysis, such as the expected
average or peak BPM, in addition to verifying the widget exists. Use the test’s
existing analysis data and appropriate finder or text assertion so the test
detects missing computed values.
In `@workout-logger/test/screens/workout_flow_screen_full_test.dart`:
- Around line 44-53: Strengthen the workout-flow scenarios in
workout-logger/test/screens/workout_flow_screen_full_test.dart: lines 44-53 must
seed an exercise, require LOG SET, and verify the set was logged; lines 73-82
must likewise require and verify logging in the routine-backed flow; lines
110-118 must assert an observable deload-specific target or configuration
instead of only checking WorkoutFlowScreen visibility.
In `@workout-logger/test/services/health_connect_service_test.dart`:
- Around line 140-156: Update the test around HealthConnectService.isAvailable
to use a successful delayed platform response after 200ms and expect available
to be true, verifying the delayed success path within the deadline. If the null
response must remain, rename the test to describe unavailable-platform behavior
instead.
In `@workout-logger/test/test_utils/test_harness.dart`:
- Around line 82-86: Update the teardown callback registered by addTearDown to
be async and await tester.binding.setSurfaceSize(null), while preserving the
existing physical-size and device-pixel-ratio resets.
In `@workout-logger/test/test_utils/test_robot.dart`:
- Line 16: Update the TestRobot constructor to be const, preserving its existing
tester initialization and final-field behavior.
In `@workout-logger/test/userflow_history_and_session_details_test.dart`:
- Around line 73-75: Update the test setup around tester.view.devicePixelRatio
to register tester.view.resetDevicePixelRatio with addTearDown alongside
resetPhysicalSize, ensuring the binding restores both view properties after the
test.
In `@workout-logger/test/userflow_program_design_and_generator_test.dart`:
- Around line 55-67: Make the required UI interactions and outcome assertions
mandatory across the user-flow tests: in
workout-logger/test/userflow_program_design_and_generator_test.dart#L55-L67,
require both TextField controls and Save Program, then verify the entered
program persisted; at `#L70-L106`, load and open the program created through the
UI instead of directly saving sampleProgram; at `#L120-L135`, require the
suggestion and generate controls and assert the expected API-configuration
result. In workout-logger/test/userflow_screens_sweep_test.dart#L149-L163,
assert the required field and actions before invoking the sweep helper. In
workout-logger/test/userflow_targets_and_muscle_sheets_full_test.dart#L138-L154,
assert the required builder controls and verify a persisted or rendered result
after saving.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 20f22fbd-fd47-436c-94fe-6bbd6251f463
⛔ Files ignored due to path filters (1)
workout-logger/pubspec.lockis excluded by!**/*.lock
📒 Files selected for processing (77)
.codecov.yml.github/workflows/release.yml.github/workflows/test.yml.gitignoreREADME.mdworkout-logger/.gitignoreworkout-logger/android/app/build.gradle.ktsworkout-logger/android/app/proguard-rules.proworkout-logger/android/gradle.propertiesworkout-logger/android/gradle/wrapper/gradle-wrapper.propertiesworkout-logger/android/key.properties.exampleworkout-logger/android/settings.gradle.ktsworkout-logger/fastlane/metadata/android/en-US/full_description.txtworkout-logger/lib/screens/edit_workout_session_screen.dartworkout-logger/lib/screens/home_screen.dartworkout-logger/lib/screens/programs/import_program_screen.dartworkout-logger/lib/screens/widgets/floating_nav_bar.dartworkout-logger/lib/screens/widgets/health_detail_shell.dartworkout-logger/lib/screens/widgets/readiness_card.dartworkout-logger/lib/screens/widgets/rf_dialogs.dartworkout-logger/lib/screens/widgets/rf_widgets.dartworkout-logger/lib/screens/widgets/routine_creator.dartworkout-logger/lib/screens/workout_flow_screen.dartworkout-logger/lib/services/health_connect_service.dartworkout-logger/pubspec.yamlworkout-logger/scripts/build_release.pyworkout-logger/test/api_service_test.dartworkout-logger/test/debug_log_buffer_test.dartworkout-logger/test/gemini_context_builder_test.dartworkout-logger/test/screens/ai_coach_screen_full_test.dartworkout-logger/test/screens/ai_coach_screen_test.dartworkout-logger/test/screens/ai_program_generator_screen_test.dartworkout-logger/test/screens/edit_workout_session_screen_test.dartworkout-logger/test/screens/heart_rate_detail_screen_test.dartworkout-logger/test/screens/history_screen_test.dartworkout-logger/test/screens/home_screen_test.dartworkout-logger/test/screens/onboarding_screen_test.dartworkout-logger/test/screens/profile_screen_full_test.dartworkout-logger/test/screens/profile_screen_test.dartworkout-logger/test/screens/programs/program_designer_screen_test.dartworkout-logger/test/screens/programs/programs_screens_test.dartworkout-logger/test/screens/settings_screen_test.dartworkout-logger/test/screens/sleep_detail_screen_test.dartworkout-logger/test/screens/widgets/editable_exercise_card_full_test.dartworkout-logger/test/screens/widgets/health_bar_chart_test.dartworkout-logger/test/screens/widgets/health_cards_test.dartworkout-logger/test/screens/widgets/health_widgets_test.dartworkout-logger/test/screens/widgets/rf_cards_test.dartworkout-logger/test/screens/widgets/rf_dialogs_test.dartworkout-logger/test/screens/widgets/rf_widgets_test.dartworkout-logger/test/screens/widgets/routine_creator_test.dartworkout-logger/test/screens/widgets/targets_tab_test.dartworkout-logger/test/screens/widgets/workout_hr_section_test.dartworkout-logger/test/screens/workout_flow_screen_full_test.dartworkout-logger/test/screens/workout_flow_screen_test.dartworkout-logger/test/services/health_connect_service_test.dartworkout-logger/test/settings_provider_test.dartworkout-logger/test/sleep_hr_builder_test.dartworkout-logger/test/sleep_hr_models_test.dartworkout-logger/test/storage_service_test.dartworkout-logger/test/test_utils/stub_health_connect_service.dartworkout-logger/test/test_utils/test_fixtures.dartworkout-logger/test/test_utils/test_harness.dartworkout-logger/test/test_utils/test_robot.dartworkout-logger/test/test_utils/test_sweep.dartworkout-logger/test/userflow_ai_coach_and_gemini_service_test.dartworkout-logger/test/userflow_health_and_profile_screen_test.dartworkout-logger/test/userflow_history_and_session_details_test.dartworkout-logger/test/userflow_program_design_and_generator_test.dartworkout-logger/test/userflow_programs_screen_deep_test.dartworkout-logger/test/userflow_routine_creation_test.dartworkout-logger/test/userflow_screens_sweep_test.dartworkout-logger/test/userflow_services_and_ai_sweep_test.dartworkout-logger/test/userflow_settings_and_storage_test.dartworkout-logger/test/userflow_targets_and_muscle_sheets_full_test.dartworkout-logger/test/userflow_targets_and_muscle_sheets_test.dartworkout-logger/test/userflow_workout_logging_test.dart
💤 Files with no reviewable changes (1)
- workout-logger/lib/screens/programs/import_program_screen.dart
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| uses: actions/checkout@v7 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Workflow relevant lines:"
for f in .github/workflows/release.yml .github/workflows/test.yml; do
if [ -f "$f" ]; then
echo "--- $f"
grep -n 'uses:\|pin|full commit|commit hash' "$f" || true
fi
done
echo
echo "All action refs in workflows:"
python3 - <<'PY'
import pathlib, re
for p in sorted(pathlib.Path('.github/workflows').glob('*.yml')) + sorted(pathlib.Path('.github/workflows').glob('*.yaml')):
for i,line in enumerate(p.read_text().splitlines(),1):
m=re.search(r'uses:\s*([^#\s]+)\s*#?\s*(.*)', line.strip())
if m:
print(f"{p}:{i}: {m.group(1)}")
PYRepository: Devasy/RepForge
Length of output: 1190
🌐 Web query:
GitHub Actions recommended secure workflow pinning commit SHA version tags
💡 Result:
To secure GitHub Actions workflows against supply chain attacks, GitHub and security experts strongly recommend pinning actions to a full-length (40-character) commit SHA [1][2][3][4]. Why Pinning to Commit SHAs is Necessary Standard version tags (e.g., @v4) are mutable references [3][4][5]. If an action's repository is compromised, an attacker can overwrite these tags to point to malicious code, which your workflows would then automatically execute [6][3][4][7]. Because Git tags can be moved or deleted, they do not guarantee that the code running today is the same code you audited previously [8][5][9]. A full-length commit SHA, by contrast, is a unique, immutable cryptographic digest [6][8][9]. Pinning to a specific SHA ensures your workflow always executes the exact code you intended, preventing silent, malicious updates [6][4][5][9]. Recommended Implementation To maintain both security and ease of maintenance, follow these best practices: 1. Use Full-Length SHAs: Always use the 40-character full commit SHA. Never use shortened SHAs, as they are susceptible to collision attacks [1][2][8]. 2. Keep Human-Readable References: Include the version tag as a trailing comment in your workflow file (e.g., uses: actions/checkout@a1b2c3d4e5f6... # v4.2.0) [3][4][9]. This allows automated dependency management tools like Dependabot and Renovate to detect new versions and open pull requests, ensuring you can update your actions securely while maintaining immutability [3][4][7]. 3. Enforce via Policy: If you are an administrator, you can enforce this security standard across your organization or enterprise by enabling the GitHub Actions policy that requires actions to be pinned to a full-length commit SHA [6][2][5]. When enabled, any workflow using a mutable reference (tags or branches) will fail [6][5]. Security Note: While SHA pinning prevents tag-retargeting attacks, it does not protect against code that was already malicious at the time of the initial pin [7]. Always continue to vet the actions and authors you choose to include in your pipelines [10][11].
Citations:
- 1: https://docs.github.com/en/enterprise-server@2.22/actions/security-guides/security-hardening-for-github-actions
- 2: https://github.com/github/docs/blob/main/content/actions/reference/security/secure-use.md
- 3: https://starsling.dev/best-practices/github-actions/pin-action-shas
- 4: https://tomodahinata.com/en/blog/dependabot-github-actions-sha-pinning-supply-chain-security-guide
- 5: https://www.romainlespinasse.dev/posts/github-actions-commit-sha-pinning/
- 6: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/
- 7: https://emmer.dev/blog/pin-your-github-actions-to-protect-against-mutability/
- 8: https://docs.github.com/en/actions/how-tos/create-and-publish-actions/manage-custom-actions
- 9: https://tenthirtyam.org/dispatches/2026/03/27/why-you-should-pin-github-actions-to-commit-hashes/
- 10: https://docs.github.com/en/actions/reference/security/secure-use
- 11: https://blog.gitguardian.com/github-actions-security-cheat-sheet/
🌐 Web query:
actions/checkout release v5 v4 tag commit SHA
💡 Result:
In the actions/checkout repository, both v4 and v5 are major release versions [1][2]. The transition from v4 to v5 primarily involved updating the underlying Node.js runtime from Node.js 20 to Node.js 24 [3][4][5]. This update requires the use of GitHub Actions runners with version v2.327.1 or higher [5]. Regarding the use of "tag" or "commit SHA" with these versions: 1. Usage: You can reference any specific version (v4, v5, v6, v7, etc.) in your workflow file using the syntax actions/checkout@v [4][6][2]. 2. Specifying Ref/SHA: Regardless of the action version used (@v4, @v5, etc.), you can checkout a specific branch, tag, or commit SHA by using the ref input [2][7]. Example: - uses: actions/checkout@v5 with: ref: By default, the action checks out the ref or SHA that triggered the workflow [5][2]. Specifying a ref in the with block allows you to override this default behavior [2][7].
Citations:
- 1: https://github.com/actions/checkout/releases
- 2: https://github.com/actions/checkout/?tab=readme-ov-file
- 3: Prepare v5.0.0 release actions/checkout#2238
- 4: actions/checkout@08eba0b...08c6903
- 5: https://github.com/actions/checkout
- 6: actions/checkout@v4...v5.0.0
- 7: https://github.com/actions/checkout/blob/main/README.md
Pin the remaining GitHub Actions to full commit hashes.
The listed mutable action tags can move or be replaced, changing pipeline behavior without a repository commit. Pin each action to a full 40-character commit SHA and keep the release name in a trailing comment.
🧰 Tools
🪛 zizmor (1.29.0)
[error] 25-25: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
📍 Affects 2 files
.github/workflows/release.yml#L25-L25(this comment).github/workflows/release.yml#L31-L31.github/workflows/release.yml#L37-L37.github/workflows/release.yml#L164-L164.github/workflows/test.yml#L29-L29
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/release.yml at line 25, Pin every listed GitHub Action to
a full 40-character commit SHA instead of a mutable tag, preserving the action
release name in a trailing comment. Apply this to .github/workflows/release.yml
lines 25-25, 31-31, 37-37, and 164-164, and .github/workflows/test.yml line
29-29.
Source: Linters/SAST tools
| if [ -z "${{ secrets.KEYSTORE_BASE64 }}" ]; then | ||
| echo "Error: KEYSTORE_BASE64 secret is not configured in repository secrets." | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Validate all release-signing secrets before the build.
Lines 127-130 validate only KEYSTORE_BASE64. The Gradle signing contract also requires KEY_STORE_PASSWORD, KEY_ALIAS, and KEY_PASSWORD. If any of these values are missing, Gradle falls back to the debug key and the workflow can publish debug-signed APKs as a release.
Proposed fix
- name: Decode release keystore
+ env:
+ KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
+ KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }}
+ KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
+ KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
- if [ -z "${{ secrets.KEYSTORE_BASE64 }}" ]; then
- echo "Error: KEYSTORE_BASE64 secret is not configured in repository secrets."
- exit 1
- fi
- echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > /tmp/repforge-release.jks
+ : "${KEYSTORE_BASE64:?KEYSTORE_BASE64 is not configured}"
+ : "${KEY_STORE_PASSWORD:?KEY_STORE_PASSWORD is not configured}"
+ : "${KEY_ALIAS:?KEY_ALIAS is not configured}"
+ : "${KEY_PASSWORD:?KEY_PASSWORD is not configured}"
+ printf '%s' "$KEYSTORE_BASE64" | base64 --decode > /tmp/repforge-release.jks📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if [ -z "${{ secrets.KEYSTORE_BASE64 }}" ]; then | |
| echo "Error: KEYSTORE_BASE64 secret is not configured in repository secrets." | |
| exit 1 | |
| fi | |
| - name: Decode release keystore | |
| env: | |
| KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }} | |
| KEY_STORE_PASSWORD: ${{ secrets.KEY_STORE_PASSWORD }} | |
| KEY_ALIAS: ${{ secrets.KEY_ALIAS }} | |
| KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} | |
| run: | | |
| : "${KEYSTORE_BASE64:?KEYSTORE_BASE64 is not configured}" | |
| : "${KEY_STORE_PASSWORD:?KEY_STORE_PASSWORD is not configured}" | |
| : "${KEY_ALIAS:?KEY_ALIAS is not configured}" | |
| : "${KEY_PASSWORD:?KEY_PASSWORD is not configured}" | |
| printf '%s' "$KEYSTORE_BASE64" | base64 --decode > /tmp/repforge-release.jks |
🧰 Tools
🪛 zizmor (1.29.0)
[warning] 127-127: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/release.yml around lines 127 - 130, Extend the
release-signing validation block in the workflow to check KEYSTORE_BASE64,
KEY_STORE_PASSWORD, KEY_ALIAS, and KEY_PASSWORD before the build. Fail
immediately with a clear configuration error if any required secret is empty,
preventing the Gradle release task from proceeding with debug signing.
| KEY_ALIAS: ${{ secrets.KEY_ALIAS }} | ||
| KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }} | ||
| run: flutter build apk --release --split-per-abi | ||
| run: flutter build apk --release --split-per-abi --obfuscate --split-debug-info=build/app/outputs/symbols |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg '(^|/)release\.yml$|workflow|flutter|build|artifact|symbol|crash' || true
echo
echo "== release workflow around build/artifact/release =="
if [ -f .github/workflows/release.yml ]; then
nl -ba .github/workflows/release.yml | sed -n '1,240p'
fi
echo
echo "== search for build/app/outputs/symbols and symbol upload mentions =="
rg -n "split-debug-info|build/app/outputs/symbols|flutter symbol|firebase crash|sentry|crash" .github . -g '!**/*.png' -g '!**/*.svg' || true
echo
echo "== workflow uses/references related to symbols/artifacts =="
rg -n "upload-artifact|download-artifact|split-debug-info|split-per-abi|obfuscate" . -g '*.yml' -g '*.yaml' || trueRepository: Devasy/RepForge
Length of output: 840
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== release workflow lines =="
if [ -f .github/workflows/release.yml ]; then
awk '{printf "%6d\t%s\n", NR, $0}' .github/workflows/release.yml | sed -n '1,240p'
fi
echo
echo "== search for symbol-related references =="
rg -n "split-debug-info|build/app/outputs/symbols|flutter symbol|firebase crash|sentry|crash|upload-artifact|download-artifact|split-per-abi|obfuscate" .github workout-logger scripts . -g '*.yml' -g '*.yaml' -g '*.py' -g '*.gradle*' -g '*.dart' -g '!**/*.png' -g '!**/*.svg' || trueRepository: Devasy/RepForge
Length of output: 10250
🌐 Web query:
Flutter build apk --split-debug-info output location documentation
💡 Result:
When running a Flutter build with the --split-debug-info flag, the output location for debug symbols is determined by the directory path you explicitly provide as an argument to the flag [1][2]. The flag syntax is: flutter build --split-debug-info=/ [1][2] Key details regarding the output location: - User-Defined Path: You specify the directory path where Flutter should save the symbol files [1][2]. For example, using --split-debug-info=out/android will create a directory named out/android (relative to your project root) and place the generated symbol files there [3][2]. - Not Automatic: Flutter does not place these symbols in a default build folder unless you explicitly direct it to do so (e.g., --split-debug-info=build/app/outputs/symbols) [3]. - Purpose: This command generates symbol map files (e.g., app.android-arm.symbols), which are essential for de-obfuscating stack traces from crash reports [1][4][5]. - Persistence: It is recommended to store these symbols outside of ephemeral build directories (like the standard build/ folder), as they may be cleared by a flutter clean command [4]. Developers often commit these files to version control or an external symbol storage service to ensure they are available for future debugging sessions [4].
Citations:
- 1: https://docs.flutter.dev/deployment/obfuscate
- 2: https://github.com/flutter/website/blob/main/sites/docs/src/content/deployment/obfuscate.md
- 3: https://stackoverflow.com/questions/61976886/how-to-use-split-debug-info-project-name-directory
- 4: [flutter_tools] support --split-debug-info option in android builds flutter/flutter#49650
- 5: https://codebrowser.dev/flutter/flutter/packages/flutter_tools/lib/src/commands/symbolize.dart.html
Persist the obfuscation symbol files after the APK builds.
Line 140 writes split-debug-info files to build/app/outputs/symbols, but the following steps only upload and release APK files. Upload or store those symbol files in protected long-term storage before the workflow ends.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/release.yml at line 140, Update the release workflow step
following the Flutter build command to persist the generated files from
build/app/outputs/symbols in protected long-term storage before the workflow
ends, alongside the existing APK artifacts without changing the obfuscation
build configuration.
| if: steps.flutter-action.outputs.CACHE-HIT != 'true' | ||
| working-directory: ./workout-logger | ||
| run: flutter pub get |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow excerpt =="
sed -n '1,140p' .github/workflows/test.yml 2>/dev/null || true
echo
echo "== related files =="
git ls-files | rg '(^|/)(pubspec\.yaml|\.dart_tool/package_config\.json|workflows/test\.yml)$' || true
echo
echo "== pubspec/package_config references =="
rg -n "pubspec|package_config|flutter pub get|CACHE-HIT|flutter-analyz|flutter test" .github workout-logger pubspec.yaml 2>/dev/null || true
echo
echo "== git status =="
git status --shortRepository: Devasy/RepForge
Length of output: 3559
🌐 Web query:
subosito flutter-action flutter analyze test cache true outputs CACHE-HIT
💡 Result:
The subosito/flutter-action GitHub Action provides CACHE-HIT and PUB-CACHE-HIT outputs that allow you to determine whether the Flutter SDK or pub dependencies were successfully retrieved from the cache [1][2][3]. These outputs are available starting from version v2.21.0 [2]. They directly reflect the cache-hit output from the underlying actions/cache steps [4][5][3]. Key details regarding these outputs: - CACHE-HIT: Indicates whether the Flutter SDK cache was a hit [1][3]. - PUB-CACHE-HIT: Indicates whether the pub dependencies cache was a hit [1][3]. - Behavior: These outputs return 'true' if there is an exact match for the cache key, and an empty string if there is a cache miss [4][6][5]. Example usage: You can use these outputs to conditionally execute steps in your workflow, such as skipping dependency installation when a cache hit occurs [7][3]: steps: - name: Set up Flutter uses: subosito/flutter-action@v2 id: flutter-action with: channel: stable cache: true - name: Conditionally run dependencies installation if: steps.flutter-action.outputs.PUB-CACHE-HIT!= 'true' run: flutter pub get - name: Continue with build run: flutter build apk Note that you must provide an id to the flutter-action step (e.g., id: flutter-action) to reference these outputs in subsequent steps [7][3].
Citations:
- 1: https://github.com/subosito/flutter-action/blob/main/action.yaml
- 2: https://github.com/subosito/flutter-action/releases/tag/v2.21.0
- 3: Add cache hit outputs subosito/flutter-action#364
- 4: https://github.com/subosito/flutter-action?tab=readme-ov-file
- 5: https://github.com/subosito/flutter-action/blob/main/README.md
- 6: https://github.com/subosito/flutter-action
- 7: feat: impl cache hit outputs subosito/flutter-action#346
🌐 Web query:
site:github.com/subosito/flutter-action action.yaml CACHE-HIT PUB-CACHE-HIT cache
💡 Result:
In the context of the subosito/flutter-action GitHub Action, CACHE-HIT and PUB-CACHE-HIT are output variables that provide information about the status of the Flutter SDK and Dart pub dependencies caches, respectively [1][2]. These outputs are defined in the action's configuration (action.yaml) to allow users to conditionally execute steps based on whether a cache was restored successfully [1][2]. Specifically: CACHE-HIT: Indicates whether the Flutter SDK cache was a hit (returns 'true' if there is an exact match for the cache key) [1]. PUB-CACHE-HIT: Indicates whether the Dart pub dependencies cache was a hit (returns 'true' if there is an exact match for the cache key) [1]. These values are sourced directly from the cache-hit output of the underlying actions/cache step used within the action [3][4]. They are commonly used in workflow YAML files to skip redundant installation or setup steps, such as bootstrapping dependencies, when a valid cache already exists [2][5]. Example usage in a workflow: - name: Set up Flutter uses: subosito/flutter-action@v2 id: flutter-action with: cache: true pub-cache: true - name: Conditionally run setup if: steps.flutter-action.outputs.PUB-CACHE-HIT!= 'true' run: dart pub get
Citations:
- 1: https://github.com/subosito/flutter-action/blob/main/action.yaml
- 2: Add cache hit outputs subosito/flutter-action#364
- 3: https://github.com/subosito/flutter-action
- 4: subosito/flutter-action@v2.20.0...v2.21.0
- 5: feat: impl cache hit outputs subosito/flutter-action#346
🌐 Web query:
site:docs.dart.dev packages flutter test analyze package_config.json pub cache
💡 Result:
Relevant official Dart/Flutter documentation:
- Packages: use
pubspec.yamlanddart pub getto resolve dependencies. [1] - Flutter package commands: use
flutter pub,flutter analyze, andflutter test; Flutter recommends these instead of the equivalent Dart commands in Flutter projects. [2] - Static analysis:
dart analyze [DIRECTORY|FILE]analyzes Dart source code. [3] - Testing: Flutter tests typically live under
test/; run them withflutter test. [4] package_config.json: Pub generates.dart_tool/package_config.json, mapping package names to their locations; workspaces use one shared file. [5]- Pub cache: recent Dart versions include
dart pub cache gcto remove packages no longer referenced by current projects. [6]
The original query returned no exact docs.dart.dev match; current documentation is primarily on dart.dev and docs.flutter.dev.
Run dependency resolution when the Flutter SDK cache hits.
CACHE-HIT reports whether the Flutter SDK cache was restored. This skips flutter pub get even when the project pub cache was not restored, leaving .dart_tool/package_config.json unresolved for flutter analyze and flutter test. Check steps.flutter-action.outputs.PUB-CACHE-HIT instead, or always run flutter pub get for clean runners.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/test.yml around lines 42 - 44, Update the condition
guarding the flutter pub get step to use
steps.flutter-action.outputs.PUB-CACHE-HIT rather than CACHE-HIT, so dependency
resolution runs when the project pub cache was not restored while preserving the
existing working-directory and command.
| slug: Devasy/RepForge | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the added empty line.
The configured YAML linter rejects the empty line after slug.
🧰 Tools
🪛 YAMLlint (1.37.1)
[error] 69-69: too many blank lines (1 > 0)
(empty-lines)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/test.yml around lines 68 - 69, Remove the empty line
immediately following the slug entry in the workflow YAML, leaving the slug
configuration and surrounding formatting otherwise unchanged.
Source: Linters/SAST tools
| test('HealthConnectService succeeds when platform response takes > 100ms within deadline', () async { | ||
| const channel = 'dev.flutter.pigeon.health_connector_hc_android.HealthConnectorHCAndroidApi.getHealthPlatformStatus'; | ||
| addTearDown(() { | ||
| TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMessageHandler(channel, null); | ||
| }); | ||
|
|
||
| TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMessageHandler( | ||
| channel, | ||
| (ByteData? message) async { | ||
| await Future.delayed(const Duration(milliseconds: 200)); | ||
| return null; | ||
| }, | ||
| ); | ||
|
|
||
| final service = HealthConnectService(); | ||
| final available = await service.isAvailable(); | ||
| expect(available, isFalse); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Test the delayed success path or rename this test.
The handler returns null, and Line 156 expects false. This test does not verify that a delayed successful platform response completes within the deadline. An implementation that always returns false passes this test.
Configure a successful platform response and expect true. If failure is the intended case, rename the test to describe unavailable-platform behavior.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@workout-logger/test/services/health_connect_service_test.dart` around lines
140 - 156, Update the test around HealthConnectService.isAvailable to use a
successful delayed platform response after 200ms and expect available to be
true, verifying the delayed success path within the deadline. If the null
response must remain, rename the test to describe unavailable-platform behavior
instead.
| addTearDown(() { | ||
| tester.view.resetPhysicalSize(); | ||
| tester.view.resetDevicePixelRatio(); | ||
| tester.binding.setSurfaceSize(null); | ||
| }); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect all test surface-size setup and teardown calls.
rg -n -C 3 'setSurfaceSize\(|addTearDown\(' workout-logger/testRepository: Devasy/RepForge
Length of output: 3600
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate flutter test harness source to inspect setSurfaceSize contract and widget tester method signatures.
rg -n "Future<void>\s+setSurfaceSize|setSurfaceSize\(" --glob '*flutter*' --glob '*test*' /tmp 2>/dev/null || true
python3 - <<'PY'
import subprocess, sys, re, pathlib
try:
out=subprocess.check_output(["dart", "--version"], text=True, stderr=subprocess.STDOUT)
print("dart_version", out.strip())
except Exception as e:
print("dart_unavailable", repr(e))
try:
out=subprocess.check_output(["flutter", "--version"], text=True, stderr=subprocess.STDOUT)
print("flutter_version", out.strip())
except Exception as e:
print("flutter_unavailable", repr(e))
PY
# Inspect TestHarness implementation around prepareTester and any docs.
nl -ba workout-logger/test/test_utils/test_harness.dart | sed -n '1,120p'Repository: Devasy/RepForge
Length of output: 331
🌐 Web query:
Flutter WidgetTester binding setSurfaceSize Future<void> await signature
💡 Result:
The setSurfaceSize method is a member of the TestWidgetsFlutterBinding class in the flutter_test library [1][2]. Its signature is as follows: Future setSurfaceSize(Size? size) [1][3] This method artificially changes the logical size of the WidgetTester.view to the specified size and flushes microtasks [1][2]. Because it returns a Future, it must be awaited when called within a test [1][3]. Key usage and implementation details include: * Awaiting the call: You should use the await keyword when calling setSurfaceSize to ensure the size change and subsequent microtask flushes are completed before proceeding with the test [1][3]. * State Management: This method affects the state of the WidgetTester.view and can leak across tests if not properly reset [1][3]. It is standard practice to reset the surface size to null (the default) after the test using addTearDown [1][3]. * Example: await binding.setSurfaceSize(someSize); addTearDown( => binding.setSurfaceSize(null)); * Deprecation Warning: Official documentation and framework source code suggest that setSurfaceSize is considered for deprecation [1][4]. It is recommended to consider using TestFlutterView.physicalSize instead, which is a more modern and flexible way to manage view configurations for any view, including the WidgetTester.view [1][3]. Top results: [1], [3], [4]
Citations:
- 1: https://api.flutter.dev/flutter/flutter_test/TestWidgetsFlutterBinding/setSurfaceSize.html
- 2: https://api.flutter.dev/flutter/flutter_test/TestWidgetsFlutterBinding-class.html
- 3: https://github.com/flutter/flutter/blob/2cf2c3d2c2/packages/flutter_test/lib/src/binding.dart
- 4: Deprecate
TestWidgetsFlutterBinding.setSurfaceSizeflutter/flutter#123881
🏁 Script executed:
#!/bin/bash
set -euo pipefail
cat -n workout-logger/test/test_utils/test_harness.dart | sed -n '68,90p'Repository: Devasy/RepForge
Length of output: 878
Await the setSurfaceSize(null) reset in teardown.
tester.binding.setSurfaceSize returns a Future<void>, and the setup awaits it; call addTearDown with an async callback and await the same reset to keep the fixture restoration consistent.
Proposed fix
- addTearDown(() {
+ addTearDown(() async {
tester.view.resetPhysicalSize();
tester.view.resetDevicePixelRatio();
- tester.binding.setSurfaceSize(null);
+ await tester.binding.setSurfaceSize(null);
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| addTearDown(() { | |
| tester.view.resetPhysicalSize(); | |
| tester.view.resetDevicePixelRatio(); | |
| tester.binding.setSurfaceSize(null); | |
| }); | |
| addTearDown(() async { | |
| tester.view.resetPhysicalSize(); | |
| tester.view.resetDevicePixelRatio(); | |
| await tester.binding.setSurfaceSize(null); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@workout-logger/test/test_utils/test_harness.dart` around lines 82 - 86,
Update the teardown callback registered by addTearDown to be async and await
tester.binding.setSurfaceSize(null), while preserving the existing physical-size
and device-pixel-ratio resets.
| class TestRobot { | ||
| final WidgetTester tester; | ||
|
|
||
| TestRobot(this.tester); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Make the TestRobot constructor const.
The constructor only initializes a final field. Add const to satisfy the Dart constructor guideline.
As per coding guidelines, use const constructors wherever possible.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@workout-logger/test/test_utils/test_robot.dart` at line 16, Update the
TestRobot constructor to be const, preserving its existing tester initialization
and final-field behavior.
Source: Coding guidelines
| tester.view.physicalSize = const Size(800, 1800); | ||
| tester.view.devicePixelRatio = 1.0; | ||
| addTearDown(tester.view.resetPhysicalSize); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files matching target:"
fd -a 'userflow_history_and_session_details_test.dart' . || true
file="$(fd 'userflow_history_and_session_details_test.dart' . | head -n1 || true)"
if [ -n "$file" ]; then
echo "\nTarget file: $file"
wc -l "$file"
echo "\nRelevant lines:"
cat -n "$file" | sed -n '1,140p'
fi
echo "\nSearch reset device pixel ratio usages:"
rg -n "resetDevicePixelRatio|devicePixelRatio\\s*=|physicalSize\\s*=|resetPhysicalSize" workout-logger/test || trueRepository: Devasy/RepForge
Length of output: 6400
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "history_screen_test.dart relevant setup section:"
cat -n workout-logger/test/screens/history_screen_test.dart | sed -n '1,180p'
echo "\nDart Flutter View reset API availability in installed flutter_test source:"
flutter --version 2>/dev/null || true
for root in "$HOME/flutter/bin/cache/pkg/flutter_test/lib" "/opt/flutter/bin/cache/pkg/flutter_test/lib"; do
[ -d "$root/src/dart_test" ] && find "$root/src/dart_test" -type f \( -name '*view*.dart' -o -name '*binding*.dart' \) -print | sort
done
echo "\nSearch package source for View.resetDevicePixelRatio:"
find "$PWD" -path '*flutter_test*' -maxdepth 8 -type f -name '*.dart' -print 2>/dev/null | xargs rg -n "resetDevicePixelRatio|class View|devicePixelRatio" 2>/dev/null || true
# Determine current binding type by source presence only.
python3 - <<'PY'
from pathlib import Path
roots=["src/flutter_test","test/flutter_test"]
for r in roots:
if (Path(r)).exists():
print(f"FOUND_PREFIX {r}")
PYRepository: Devasy/RepForge
Length of output: 3951
Reset the test view device pixel ratio.
This helper changes tester.view.devicePixelRatio but only adds teardown for physical size, so tests run in the same binding can inherit 1.0. Add teardown for tester.view.resetDevicePixelRatio.
Proposed fix
tester.view.physicalSize = const Size(800, 1800);
tester.view.devicePixelRatio = 1.0;
addTearDown(tester.view.resetPhysicalSize);
+ addTearDown(tester.view.resetDevicePixelRatio);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| tester.view.physicalSize = const Size(800, 1800); | |
| tester.view.devicePixelRatio = 1.0; | |
| addTearDown(tester.view.resetPhysicalSize); | |
| tester.view.physicalSize = const Size(800, 1800); | |
| tester.view.devicePixelRatio = 1.0; | |
| addTearDown(tester.view.resetPhysicalSize); | |
| addTearDown(tester.view.resetDevicePixelRatio); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@workout-logger/test/userflow_history_and_session_details_test.dart` around
lines 73 - 75, Update the test setup around tester.view.devicePixelRatio to
register tester.view.resetDevicePixelRatio with addTearDown alongside
resetPhysicalSize, ensuring the binding restores both view properties after the
test.
| final textFields = find.byType(TextField); | ||
| if (textFields.evaluate().length >= 2) { | ||
| await tester.enterText(textFields.at(0), 'Strength Block 1'); | ||
| await tester.enterText(textFields.at(1), '4-week progressive overload'); | ||
| await tester.pumpAndSettle(); | ||
| } | ||
|
|
||
| // Tap Save Program button | ||
| final saveBtn = find.text('Save Program'); | ||
| if (saveBtn.evaluate().isNotEmpty) { | ||
| await tester.tap(saveBtn); | ||
| await tester.pumpAndSettle(); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Make required UI actions mandatory in these user-flow tests.
Each listed test can pass when required controls are missing because it skips interactions when a finder is empty. The designer test then saves sampleProgram directly, so it does not verify that the UI save action persisted the entered program.
workout-logger/test/userflow_program_design_and_generator_test.dart#L55-L67: require the fields andSave Program, then assert that the entered program was persisted.workout-logger/test/userflow_program_design_and_generator_test.dart#L70-L106: load and open the program created by the UI instead of savingsampleProgramdirectly.workout-logger/test/userflow_program_design_and_generator_test.dart#L120-L135: require the suggestion and generate action, then assert the expected API-configuration result.workout-logger/test/userflow_screens_sweep_test.dart#L149-L163: assert the required field and actions before invoking the sweep helper.workout-logger/test/userflow_targets_and_muscle_sheets_full_test.dart#L138-L154: assert required builder controls and a persisted or rendered result after saving.
📍 Affects 3 files
workout-logger/test/userflow_program_design_and_generator_test.dart#L55-L67(this comment)workout-logger/test/userflow_program_design_and_generator_test.dart#L70-L106workout-logger/test/userflow_program_design_and_generator_test.dart#L120-L135workout-logger/test/userflow_screens_sweep_test.dart#L149-L163workout-logger/test/userflow_targets_and_muscle_sheets_full_test.dart#L138-L154
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@workout-logger/test/userflow_program_design_and_generator_test.dart` around
lines 55 - 67, Make the required UI interactions and outcome assertions
mandatory across the user-flow tests: in
workout-logger/test/userflow_program_design_and_generator_test.dart#L55-L67,
require both TextField controls and Save Program, then verify the entered
program persisted; at `#L70-L106`, load and open the program created through the
UI instead of directly saving sampleProgram; at `#L120-L135`, require the
suggestion and generate controls and assert the expected API-configuration
result. In workout-logger/test/userflow_screens_sweep_test.dart#L149-L163,
assert the required field and actions before invoking the sweep helper. In
workout-logger/test/userflow_targets_and_muscle_sheets_full_test.dart#L138-L154,
assert the required builder controls and verify a persisted or rendered result
after saving.
Release 2.1.0 Final PR
Add proper changelogs
Summary by CodeRabbit